import asyncio
import random
import time
import datetime
from fastapi import Depends, Request
from fastapi.responses import JSONResponse
from fastapi_jwt_auth import AuthJWT
from typing import Literal

from common.base.base_routers import get_custom_router
from services.server_integration.api import ServerIntegrationApi
from services.automatic_control.api import AutomaticControlApi
from services.server_integration.schemas.full_unit_configuration import FullUnitConfiguration
from new_auth.schemas.auth import auth
from services.server_integration.schemas.calibrate_status import CalibrateHistoryInfo
from .schemas.alarms_request import AlarmsRequest, AlarmsRequestCount
from .schemas.alarms_response_configuration import AlarmResponseConfiguration
from .schemas.alarms import Alarm
from .schemas.cities_timezone import TimezonesRequest, CityTimezone, CityByTimezoneRequest
from services.server_integration.router_handler import ServerIntegrationRouterHandler
from sse_starlette.sse import EventSourceResponse
from common.third_party.save_config import load_config, save_config
from common.third_party.dkg import validate
from auth import db


sir_handler = ServerIntegrationRouterHandler()
si_api = ServerIntegrationApi()
ac_api = AutomaticControlApi()
server_integration_router = get_custom_router(
    si_api, prefix='/server_integration', tags=['server_integration'], base_routers=False
)


@server_integration_router.post('/set-production-state', response_class=JSONResponse)
async def set_production_state(state: bool, request: Request, authorize: AuthJWT = Depends()):
    is_user, user_role = await auth(authorize, request)
    if user_role != 'adjuster':
        return 'expected adjuster'

    return await si_api.set_production_state(state)


@server_integration_router.post('/get-production-state', response_class=JSONResponse)
async def get_production_state(request: Request, authorize: AuthJWT = Depends()):
    is_user, user_role = await auth(authorize, request)
    return await si_api.get_production_state()


@server_integration_router.post('/set-full-unit-configuration', response_class=JSONResponse)
async def set_full_unit_configuration(config: FullUnitConfiguration, request: Request, authorize: AuthJWT = Depends()):
    is_user, user_role = await auth(authorize, request)
    return await si_api.set_full_configuration(config, user_role)


@server_integration_router.get('/get-full-unit-configuration', response_class=JSONResponse)
async def get_full_unit_configuration(request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    return await si_api.get_full_configuration()


@server_integration_router.get('/start-calibrate', response_class=JSONResponse)
async def start_calibrate(request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    return await si_api.start_calibrate()


@server_integration_router.get('/special-calibrate', response_class=JSONResponse)
async def special_calibrate(
        device: Literal['RM0', 'RM1', 'SM0', 'SM1', 'SM2', 'SM3', 'BS0', 'BS1', 'BS2', 'BS3'],
        request: Request,
        power: float, authorize: AuthJWT = Depends()
):
    is_user, user_role = await auth(authorize, request)
    if user_role != 'adjuster':
        return 'expected adjuster'

    return await si_api.special_calibrate(device, power)


@server_integration_router.get('/set-ac-magic-numbers', response_class=JSONResponse)
async def set_ac_magic_numbers(
        device: Literal['RM0', 'RM1', 'SM0', 'SM1', 'SM2', 'SM3', 'BS0', 'BS1', 'BS2', 'BS3'],
        correct_number: float, real_power: float, power: float,
        request: Request,
        authorize: AuthJWT = Depends()
):
    is_user, user_role = await auth(authorize, request)
    if user_role != 'adjuster':
        return 'expected adjuster'

    return await si_api.set_ac_magic_numbers(device, correct_number, real_power, power)


@server_integration_router.get('/get-ac-magic-numbers', response_class=JSONResponse)
async def get_ac_magic_numbers(
        device: Literal['RM0', 'RM1', 'SM0', 'SM1', 'SM2', 'SM3', 'BS0', 'BS1', 'BS2', 'BS3'],
        request: Request,
        authorize: AuthJWT = Depends()
):
    await auth(authorize, request)
    return await si_api.get_ac_magic_numbers(device)


@server_integration_router.get('/get-all-ac-magic-numbers', response_class=JSONResponse)
async def get_all_ac_magic_numbers(request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    result = [
        await si_api.get_ac_magic_numbers('RM0'),
        await si_api.get_ac_magic_numbers('RM1'),
        await si_api.get_ac_magic_numbers('SM0'),
        await si_api.get_ac_magic_numbers('SM1'),
        await si_api.get_ac_magic_numbers('SM2'),
        await si_api.get_ac_magic_numbers('SM3'),
    ]
    return result


@server_integration_router.get('/set-rtr-normal-vswr', response_class=JSONResponse)
async def set_rtr_normal_vswr(index: int, vswr: float, request: Request, authorize: AuthJWT = Depends()):
    is_user, user_role = await auth(authorize, request)
    if user_role != 'adjuster':
        return 'expected adjuster'

    return await si_api.set_rtr_normal_vswr(index, vswr)


@server_integration_router.get('/get-rtr-normal-vswr', response_class=JSONResponse)
async def get_rtr_normal_vswr(index: int, request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    return await si_api.get_rtr_normal_vswr(index)


@server_integration_router.get('/get-all-rtr-normal-vswr', response_class=JSONResponse)
async def get_all_rtr_normal_vswr(request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    return [await si_api.get_rtr_normal_vswr(0), await si_api.get_rtr_normal_vswr(1)]


@server_integration_router.get('/calibrate-rtr-vswr', response_class=JSONResponse)
async def calibrate_rtr_vswr(index: int, request: Request, authorize: AuthJWT = Depends()) -> float | None | str:
    is_user, user_role = await auth(authorize, request)
    if user_role != 'adjuster':
        return 'expected adjuster'

    return await si_api.calibrate_rtr_vswr(index)


@server_integration_router.get('/get-telemetry', response_class=JSONResponse)
async def get_unit_technical_parameters_status(request: Request, server_user_role: str = None, authorize: AuthJWT = Depends()):
    is_user, user_role = await auth(authorize, request)

    return await si_api.get_technical_status()


@server_integration_router.post('/get-current-alarms', response_class=JSONResponse)
async def get_current_alarms(alarm_request: AlarmsRequest, request: Request, server_user_role: str = None, authorize: AuthJWT = Depends()):
    is_user, user_role = await auth(authorize, request)
    if user_role == 'server' and server_user_role == 'adjuster':
        user_role = server_user_role

    return await si_api.get_current_alarms(alarm_request, user_role)


@server_integration_router.post('/get-alarms-log', response_class=JSONResponse)
async def get_alarms_log(alarm_request: AlarmsRequest, request: Request, server_user_role: str = None, authorize: AuthJWT = Depends()):
    is_user, user_role = await auth(authorize, request)
    if user_role == 'server' and server_user_role == 'adjuster':
        user_role = server_user_role

    return await si_api.get_alarms_log(alarm_request, user_role)


@server_integration_router.get('/get-newest-oldest-alarms-date', response_class=JSONResponse)
async def get_newest_oldest_alarms_date(request: Request, authorize: AuthJWT = Depends()):
    is_user, user_role = await auth(authorize, request)
    return await si_api.get_newest_oldest_alarms_date(user_role)


@server_integration_router.get('/load-alarms-descriptions', response_class=JSONResponse)
async def load_alarms_descriptions(request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    return await si_api.load_alarms_descriptions()


@server_integration_router.post('/get_cities_timezones', response_class=JSONResponse)
async def get_cities_timezones(timezone_request: TimezonesRequest, request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    return await si_api.get_cities_timezones(timezone_request)


@server_integration_router.post('/get_city_by_timezone', response_class=JSONResponse)
async def get_city_by_timezone(city_request: CityByTimezoneRequest, request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    return await si_api.get_city_by_timezone(city_request)


@server_integration_router.post('/get-cviya-list', response_class=JSONResponse)
async def get_cviya_fsr_list(request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    return await si_api.get_cviya_list()


@server_integration_router.get('/reboot-motherboard', response_class=JSONResponse)
async def reboot_motherboard(request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    return await si_api.reboot_motherboard()


@server_integration_router.get('/reboot-power', response_class=JSONResponse)
async def reboot_power(request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    return await si_api.reboot_power()


@server_integration_router.get('/aping', response_class=JSONResponse)
async def aping(request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    return 'pong'


@server_integration_router.get('/clear-alarms', response_class=JSONResponse)
async def clear_alarms(request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    return await si_api.clear_alarms()


@server_integration_router.get('/stop-calibration', response_class=JSONResponse)
async def stop_calibration(request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    return await ac_api.stop_calibration()


@server_integration_router.get('/get-calibrate-history', response_class=JSONResponse)
async def get_calibrate_history(language: Literal['ru', "en"], request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    timez = datetime.timezone(datetime.timedelta(hours=await si_api.get_timezone()))
    result = await ac_api.get_calibrate_history()

    result.messages = list(map(lambda x: x.with_timed_msg(timez, language), result.messages))
    return result


@server_integration_router.get('/get-calibrate-history-info', response_class=JSONResponse)
async def get_calibrate_history_info(request: Request, authorize: AuthJWT = Depends()):
    await auth(authorize, request)
    unit_configuration = (await si_api.get_full_configuration()).unit_configuration
    result = await ac_api.get_calibrate_history()

    return CalibrateHistoryInfo(
        date=result.date,
        calibration_state=unit_configuration.calibration_state,
        ustirovka_state=unit_configuration.ustirovka_state,
        simulation_state=unit_configuration.simulation_state
    )


@server_integration_router.get('/calibrate-status')
async def calibrate_status_stream(language: Literal['ru', "en"], request: Request):
    queue_id = next(
        filter(
            lambda x: x not in sir_handler.cg_queues,
            range(0, 5_000)
        )
    )
    sir_handler.cg_queues[queue_id] = asyncio.Queue()
    queue = sir_handler.cg_queues[queue_id]

    async def cleanup():
        while True:
            await asyncio.sleep(1)
            if await request.is_disconnected():
                del sir_handler.cg_queues[queue_id]
                break


    asyncio.create_task(cleanup())

    async def event_generator():
        timez = datetime.timezone(datetime.timedelta(hours=await si_api.get_timezone()))
        while True:
            if await request.is_disconnected():
                break

            msg = (await queue.get()).with_timed_msg(timez, language)

            yield dict(data=msg.json())

    return EventSourceResponse(event_generator())


@server_integration_router.get('/digital-tune-all', response_class=JSONResponse)
async def digital_tune_all(request: Request, authorize: AuthJWT = Depends()):
    is_user, user_role = await auth(authorize, request)
    if user_role != 'adjuster':
        return 'expected adjuster'

    return await si_api.digital_tune_all()


@server_integration_router.get('/get-ad-ul-dl', response_class=JSONResponse)
async def get_ad_ul_dl(request: Request, authorize: AuthJWT = Depends()):
    is_user, user_role = await auth(authorize, request)
    if user_role != 'adjuster':
        return 'expected adjuster'

    return await si_api.get_ad_ul_dl()

@server_integration_router.get('/get-actual-reference-freq-40mhz', response_class=JSONResponse)
async def get_actual_reference_freq_40mhz(request: Request, authorize: AuthJWT = Depends()):
    is_user, user_role = await auth(authorize, request)
    if user_role != 'adjuster':
        return 'expected adjuster'

    return await ac_api.get_actual_reference_freq_40mhz()

